package com.mrd.modules.redis;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;


@Component("redisClusterClient")
public class JedisClientClusterImpl {
  private static String redisCode = "utf-8";

  @Autowired
  RedisTemplate redisTemplate;

  public RedisTemplate getRedisTemplate() {
    return redisTemplate;
  }

  /* ----------- common --------- */
  /**
   * 根据表达式查询key
   * 
   * @param pattern 索引
   * @return Collection
   */
  public Collection keys(String pattern) {
    return redisTemplate.keys(pattern);
  }

  /**
   * 根据key删除缓存数据
   * 
   * @author han
   * @param key 索引
   */
  public void delete(String key) {
    redisTemplate.delete(key);
  }

  /**
   * 根据索引的集合删除数据
   * 
   * @author han
   * @param key 集合索引Collection
   */
  public void delete(Collection key) {
    redisTemplate.delete(key);
  }

  /* ----------- string --------- */
  /**
   * 根据key查询字符串
   * 
   * @param key 索引关键字
   * @param clazz 返回的对象
   * @return
   */
  public <T> T get(String key, Class clazz) {
    String value = (String) redisTemplate.opsForValue().get(key);
    return parseJson(value, clazz);
  }

  /**
   * 根据多个查询索引查询
   * 
   * @author han
   * @param keys 多个索引集合
   * @param clazz 返回的对象类型
   * @return
   */
  public List mget(Collection keys, Class clazz) {
    List values = redisTemplate.opsForValue().multiGet(keys);
    return parseJsonList(values, clazz);
  }

  /**
   * 设置字符对象
   * 
   * @param key 索引
   * @param obj 值对象
   * @param timeout 超时时间
   * @param unit 时间单位
   */
  public <T> void set(String key, T obj, Long timeout, TimeUnit unit) {
    try {
      if (obj == null) {
        return;
      }

      String value = toJson(obj);
      if (timeout != null) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
      } else {
        redisTemplate.opsForValue().set(key, value);
      }
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  /**
   * 根据索引查询，并且更新对象
   * 
   * @author han
   * @param key 索引
   * @param obj 入参对象
   * @param clazz Class
   * @return T 返回对象
   */
  public <T> T getAndSet(String key, T obj, Class clazz) {
    if (obj == null) {
      return get(key, clazz);
    }

    String value = (String) redisTemplate.opsForValue().getAndSet(key, toJson(obj));
    return parseJson(value, clazz);
  }

  public int decrement(String key, int delta) {
    Long value = redisTemplate.opsForValue().increment(key, -delta);
    return value.intValue();
  }

  public int increment(String key, int delta) {
    Long value = redisTemplate.opsForValue().increment(key, delta);
    return value.intValue();
  }

  /* ----------- list --------- */
  public int size(String key) {
    return redisTemplate.opsForList().size(key).intValue();
  }

  public List range(String key, long start, long end, Class clazz) {
    List list = redisTemplate.opsForList().range(key, start, end);
    return parseJsonList(list, clazz);
  }

  public void rightPushAll(String key, Collection<?> values, Long timeout, TimeUnit unit) {
    if (values == null || values.isEmpty()) {
      return;
    }

    redisTemplate.opsForList().rightPushAll(key, toJsonList(values));
    if (timeout != null) {
      redisTemplate.expire(key, timeout, unit);
    }
  }

  public <T> void leftPush(String key, T obj) {
    if (obj == null) {
      return;
    }

    redisTemplate.opsForList().leftPush(key, toJson(obj));
  }

  public <T> T leftPop(String key, Class clazz) {
    String value = (String) redisTemplate.opsForList().leftPop(key);
    return parseJson(value, clazz);
  }

  public void remove(String key, int count, Object obj) {
    if (obj == null) {
      return;
    }

    redisTemplate.opsForList().remove(key, count, toJson(obj));
  }

  /* ----------- zset --------- */
  public int zcard(String key) {
    return redisTemplate.opsForZSet().zCard(key).intValue();
  }

  public List zrange(String key, long start, long end, Class clazz) {
    Set set = redisTemplate.opsForZSet().range(key, start, end);
    return parseJsonList(setToList(set), clazz);
  }

  private List setToList(Set set) {
    if (set == null) {
      return null;
    }
    return new ArrayList(set);
  }

  public void zadd(String key, Object obj, double score) {
    if (obj == null) {
      return;
    }
    redisTemplate.opsForZSet().add(key, toJson(obj), score);
  }

  public void zrem(String key, Object obj) {
    if (obj == null) {
      return;
    }
    redisTemplate.opsForZSet().remove(key, toJson(obj));
  }

  public void unionStore(String destKey, Collection keys, Long timeout, TimeUnit unit) {
    if (keys == null || keys.isEmpty()) {
      return;
    }

    Object[] keyArr = keys.toArray();
    String key = (String) keyArr[0];

    Collection otherKeys = new ArrayList(keys.size() - 1);
    for (int i = 1; i < keyArr.length; i++) {
      otherKeys.add((String) keyArr[i]);
    }

    redisTemplate.opsForZSet().unionAndStore(key, otherKeys, destKey);
    if (timeout != null) {
      redisTemplate.expire(destKey, timeout, unit);
    }
  }

  /* ----------- tool methods --------- */
  public String toJson(Object obj) {
    return JSON.toJSONString(obj, SerializerFeature.SortField);
  }

  public <T> T parseJson(String json, Class clazz) {
    return (T) JSON.parseObject(json, clazz);
  }

  public List toJsonList(Collection<?> values) {
    if (values == null) {
      return null;
    }
    List result = new ArrayList();
    for (Object obj : values) {
      result.add(toJson(obj));
    }
    return result;
  }

  public List parseJsonList(List<String> list, Class clazz) {
    if (list == null) {
      return null;
    }
    List result = new ArrayList();
    for (String s : list) {
      result.add(parseJson(s, clazz));
    }
    return result;
  }

  public void set(final byte[] key, final byte[] value, final long ttl) {
    redisTemplate.execute(new RedisCallback<Void>() {
      @Override
      public Void doInRedis(RedisConnection con) {
        try {
          con.set(key, value);
          if (ttl != 0)
            con.expire(key, ttl);
        } catch (Exception ex) {
          ex.printStackTrace();
        }
        return null;
      }
    });
  }

  public byte[] getByte(final byte[] key) {
    try {
      return (byte[]) redisTemplate.execute(new RedisCallback<byte[]>() {
        @Override
        public byte[] doInRedis(RedisConnection con) {

          return con.get(key);

        }
      });
    } catch (Exception ex) {
      ex.printStackTrace();
      return null;
    }
  }
}
